package article

import (
	"bytes"
	"context"
	"fmt"
	"gitee.com/DonHz/basic-go/webook/internal/domain"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/ecodeclub/ekit"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"strconv"
	"time"
)

var statusPrivate = uint8(domain.ArticleStatusPrivate)

type S3DAO struct {
	oss *s3.S3
	GormArticleDAO
	bucket *string
}

func NewOssDAO(oss *s3.S3, db *gorm.DB) ArticleDAO {
	return &S3DAO{
		oss: oss,
		bucket: ekit.ToPtr[string]("webook-131412345"),
		GormArticleDAO: GormArticleDAO{
			db: db,
		},
	}
}

func (o *S3DAO) Sync(ctx context.Context, art Article) (int64, error) {
	var (
		id = art.Id
	)
	// 开启事务
	err := o.db.Transaction(func(tx *gorm.DB) error {
		var err error
		txDAO := NewArticleDAO(tx)
		if id == 0 {
			id, err = txDAO.Insert(ctx, art)
		} else {
			err = txDAO.UpdateByArticleId(ctx, art)
		}
		if err != nil {
			return err
		}
		// 操作线上库
		art.Id= id
		now:=time.Now().UnixMilli()
		readerArticle := ReaderArticle{art}
		readerArticle.UpdateTime = now
		readerArticle.CreateTime = now
		// 内容上传到OSS
		readerArticle.Content = ""
		return tx.Clauses(clause.OnConflict{
			Columns: []clause.Column{{Name: "id"}},
			DoUpdates: clause.Assignments(map[string]interface{}{
				"title": art.Title,
				"update_time": now,
				"status": art.Status,
			}),
		}).Create(&readerArticle).Error
	})
	if err!=nil{
		return 0, err
	}
	// 保存到oss中，需要有重试、补偿机制
	_, err=o.oss.PutObjectWithContext(ctx, &s3.PutObjectInput{
		Bucket: o.bucket,
		Key: ekit.ToPtr[string](strconv.FormatInt(art.Id, 10)),
		Body: bytes.NewReader([]byte(art.Content)),
		ContentType: ekit.ToPtr[string]("text/plain;charset=utf-8"),
	})
	if err!=nil {
		return 0, err
	}
	return id, nil
}

func (o *S3DAO) SyncStatus(ctx context.Context, art Article) error {
	now:=time.Now().UnixMilli()
	var (
		id = art.Id
		err error
	)
	err = o.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		res:=tx.Model(&Article{}).
			Where("id=? AND author_id = ?", art.Id,art.AuthorId).
			Updates(map[string]interface{}{
				"status": art.Status,
				"update_time": now,
			})
		if res.Error!=nil{
			return res.Error
		}
		if res.RowsAffected == 0 {
			// id 或者 作者id 不对
			return fmt.Errorf("更新失败，创作者非法, id: %d, authorId: %d",
				art.Id, art.AuthorId)
		}
		// 更新线上库

		res = tx.Model(&ReaderArticle{}).
			Where("id=? AND author_id = ?", art.Id, art.AuthorId).
			Updates(map[string]interface{}{
				"status":art.Status,
				"update_time": now,
			})
		if res.Error!=nil{
			return res.Error
		}
		if res.RowsAffected == 0 {
			// id 或者 作者id 不对
			return fmt.Errorf("更新失败，创作者非法, id: %d, authorId: %d",
				art.Id, art.AuthorId)
		}
		if art.Status==statusPrivate{
			_, err = o.oss.DeleteObjectWithContext(ctx, &s3.DeleteObjectInput{
				Bucket: o.bucket,
				Key: ekit.ToPtr[string](strconv.FormatInt(id, 10)),
			})
		}
		return nil
	})
	return err
}
